﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using blackhouse.BlackApart.Business.Payments;
using blackhouse.BlackApart.Business.Prices;

namespace blackhouse.BlackApart.Business.Reservations {
	public class ImpUserApartmentsReservation : IUserApartmentsReservation {

		#region Fields

		private Factory factory = Factory.Instance();

		#endregion

		#region Properties

		public int ReservationId { get; set; }
		public string ReservationNumber { get; set; }
		public IClient Client { get; set; }
		public IPaymentType Payment { get; private set; }
		public IReservationType ReservationType { get; private set; }

		public DateTime ArrivalDate { get; private set; }
		public DateTime DepartureDate { get; private set; }
		public TimeSpan ArrivalTime { get; private set; }

		public List<IReservation> Reservations { get; set; }

		public double TotalPrice { get; set; }
		public double TotalPriceWithoutRabat { get; set; }
		public float Rabat { get; set; }

		public bool VatInvoice { get; set; }

		public ReservationStatus Status { get; set; }

		public Guid Guid { get; set; }

		#endregion

		#region Constructors

		public ImpUserApartmentsReservation() {
			this.ArrivalDate = DateTime.MinValue;
			this.DepartureDate = DateTime.MinValue;
			this.ArrivalTime = TimeSpan.MinValue;
			this.Reservations = new List<IReservation>();
			this.TotalPrice = 0;
			this.TotalPriceWithoutRabat = 0;
			this.Rabat = 0;
		}

		#endregion

		#region IUserApartmentsReservation Members

		public void SetClient(string email, string phoneNumber, string firstName, string lastName, string personTitle, string userPrefferCurrency) {
			this.Client = this.factory.GetClient(0).SearchClientByEmail(email);
			if (this.Client == null) this.Client = this.factory.GetClient(0);
			this.Client.EMail = email;
			this.Client.PhoneNumber = phoneNumber;
			this.Client.FirstName = firstName;
			this.Client.LastName = lastName;
			this.Client.PersonTitle = personTitle;
			this.Client.PrefferCurrency = userPrefferCurrency;
		}

		public void SetDates(DateTime startDate, DateTime endDate) {
			this.ArrivalDate = startDate.Date + TimeSpan.FromHours(startDate.Hour);
			this.DepartureDate = endDate.Date + TimeSpan.FromHours(12);
		}

		public void SetPaymentType(Payments.IPaymentType paymentType) {
			this.Payment = paymentType;
		}

		public void SetReservationType(IReservationType reservationType) {
			this.ReservationType = reservationType;
		}

		public void SetApartment(Apartments.IApartment apartment, int numberOfPeoples) {
			IReservation reservation = apartment.GetCalendar(this.ArrivalDate.AddDays(-1), this.DepartureDate.AddDays(1)).CreateReservation();
			reservation.SetForNumberOfPeople(numberOfPeoples);
			this.Reservations.Add(reservation);
		}

		public bool Save() {

			bool saveState = true;

			if (ReservationType == null)
				throw new ArgumentNullException("Reservation type isn't set. Use SetReservationType");
			if (Payment == null || Payment.Id <= 0)
				throw new ArgumentNullException("Payment type isn't set. Use SetPaymentType");
			if (this.Client == null)
				throw new ArgumentNullException("Client isn't set. Use SetClient");
			if (ArrivalDate == DateTime.MinValue || DepartureDate == DateTime.MinValue || ArrivalDate > DepartureDate)
				throw new ArgumentNullException("Dates isn't set.");

			saveState = this.Client.Save();
			if (!saveState) return false;

			foreach (IReservation reservation in this.Reservations) {
				if (ArrivalTime != TimeSpan.MinValue)
					reservation.SetStartDate(this.ArrivalDate + ArrivalTime, true);
				else
					reservation.SetStartDate(this.ArrivalDate, true);
				reservation.SetEndDate(this.DepartureDate);
				try {
					if (saveState)
						saveState = saveState && reservation.Save();
				}
				catch (Exception) {
					saveState = false;
				}
				if (!saveState) break;
			}

			if (!saveState) {
				foreach (IReservation reservation in this.Reservations)
					reservation.Remove();
				return false;
			}

			this.CalculatePrice();

			return true;
		}

		private void CalculatePrice() {
			ComputedApartmentPrice price = new ComputedApartmentPrice(this.ArrivalDate, this.DepartureDate);
			foreach (IReservation reservation in this.Reservations) {
				price.AddApartmentPrice(reservation.Apartment, reservation.NumberOfPeople);
			}
			this.TotalPrice = price.GetPrice();
			this.TotalPriceWithoutRabat = price.GetPriceWithoutRabat();
			this.Rabat = price.GetRabat();
			//if (this.TotalPriceWithoutRabat > this.TotalPrice)
			//{
			//    this.Rabat = (float)Math.Round(100d * (this.TotalPrice / this.TotalPriceWithoutRabat - 1), 2);
			//}
			//else
			//{
			//    this.TotalPriceWithoutRabat = this.TotalPrice;
			//}
		}

		public IUserApartmentsReservation FindByNumber(string reservationNumber) {
			if (this.ReservationNumber == reservationNumber)
				return this;
			return null;
		}

		public void SendAsEMail() {
		}

		public bool IsAuthentic(Guid toCheck) {
			return this.Guid.Equals(toCheck);
		}

		public bool ChangeStatusTo(int statusId) {
			return true;
		}

		#endregion

	}
}
